package xdu.lz.stage1_basic.chapter1_threadsafe.lock;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

/**
 * 实现一个悲观锁
 */
public class MyLock implements Lock {

    // 判断当前实例对象的锁是否被占用
    private volatile boolean isLock = false;

    // 当前阻塞的线程
    private Collection<Thread> blockedThreadCollection = new ArrayList<>();

    // 记录当前线程
    private Thread currentThread;

    @Override
    public synchronized void lock() throws InterruptedException {
        //如果锁已经被抢了，则进入被通知状态
        while (isLock) {
            blockedThreadCollection.add(Thread.currentThread());
            this.wait();
        }
        //否则抢到锁，把锁置位true，并删除阻塞
        isLock = true;
        blockedThreadCollection.remove(Thread.currentThread());
        this.currentThread = Thread.currentThread();
    }



    @Override
    public synchronized void tryLock(Long mills) throws InterruptedException, TimeOutException {
        if (mills <= 0) {
            lock();
            return;
        }
        while (isLock) {
            blockedThreadCollection.add(Thread.currentThread());
            this.wait(mills);
            if (isLock) {
                throw new TimeOutException(Thread.currentThread().getName()
                        + " time out");
            }
        }

        isLock = true;
        this.currentThread = Thread.currentThread();
        blockedThreadCollection.remove(Thread.currentThread());
    }

    @Override
    public synchronized void unlock() {
        //如果已经被释放掉了，直接返回
        if(!isLock){
            return;
        }
        //必须是当前线程本身才能释放，其他不能释放！
        if (Thread.currentThread() == this.currentThread) {
            isLock = false;
            this.notify();
            System.out.println(Thread.currentThread().getName() + " release the chapter2_caslock");
        }

    }

    @Override
    public Collection<Thread> getBlockedThread() {
        //返回不可修改的集合 ，不然会被外部修改
        return Collections.unmodifiableCollection(blockedThreadCollection);
    }

    @Override
    public int getBlockedSize() {
        return blockedThreadCollection.size();
    }
}
